package com.smartleanx.module.hrm.service.companysystemtype;

import cn.hutool.core.collection.CollUtil;
import com.smartleanx.framework.common.enums.BizTypeEnum;
import com.smartleanx.framework.common.util.collection.CollectionUtils;
import com.smartleanx.module.hrm.context.EmployeeContextHolder;
import com.smartleanx.module.hrm.controller.admin.companysystem.vo.CompanySystemFileRespVo;
import com.smartleanx.module.hrm.dal.dataobject.companysystem.CompanySystemDO;
import com.smartleanx.module.hrm.dal.dataobject.companysystem.CompanySystemDeptDO;
import com.smartleanx.module.hrm.dal.dataobject.companysystememployee.CompanySystemEmployeeDO;
import com.smartleanx.module.hrm.dal.dataobject.employee.EmployeeDO;
import com.smartleanx.module.hrm.eums.companySystem.CompanySystemLearnEnum;
import com.smartleanx.module.hrm.eums.companySystem.CompanySystemTypeEnum;
import com.smartleanx.module.hrm.eums.file.BizFileTypeEnum;
import com.smartleanx.module.hrm.intergration.FileServiceProvider;
import com.smartleanx.module.hrm.service.companysystem.CompanySystemDeptService;
import com.smartleanx.module.hrm.service.companysystem.CompanySystemService;
import com.smartleanx.module.hrm.service.companysystememployee.CompanySystemEmployeeService;
import com.smartleanx.module.hrm.service.employee.EmployeeService;
import com.smartleanx.module.infra.api.file.dto.FileRefQueryDTO;
import com.smartleanx.module.infra.api.file.dto.FileRefRespDTO;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import com.smartleanx.module.hrm.controller.admin.companysystemtype.vo.*;
import com.smartleanx.module.hrm.dal.dataobject.companysystemtype.CompanySystemTypeDO;
import com.smartleanx.framework.common.pojo.PageResult;
import com.smartleanx.framework.common.util.object.BeanUtils;

import com.smartleanx.module.hrm.dal.mysql.companysystemtype.CompanySystemTypeMapper;

import static com.smartleanx.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.smartleanx.module.hrm.enums.ErrorCodeConstants.*;

/**
 * 公司制度库分类 Service 实现类
 *
 * @author 精益大师
 */
@Service
@Validated
public class CompanySystemTypeServiceImpl implements CompanySystemTypeService {

    @Resource
    private CompanySystemTypeMapper companySystemTypeMapper;
    @Resource
    @Lazy
    private EmployeeService employeeService;
    @Resource
    private CompanySystemEmployeeService companySystemEmployeeService;
    @Resource
    private CompanySystemDeptService companySystemDeptService;
    @Lazy
    @Resource
    private CompanySystemService companySystemService;
    @Resource
    private FileServiceProvider fileServiceProvider;

    @Override
    public Long createCompanySystemType(CompanySystemTypeSaveReqVO createReqVO) {
        // 插入
        CompanySystemTypeDO companySystemType = BeanUtils.toBean(createReqVO, CompanySystemTypeDO.class);
        companySystemTypeMapper.insert(companySystemType);
        // 返回
        return companySystemType.getId();
    }

    @Override
    public void updateCompanySystemType(CompanySystemTypeSaveReqVO updateReqVO) {
        // 校验存在
        validateCompanySystemTypeExists(updateReqVO.getId());
        // 更新
        CompanySystemTypeDO updateObj = BeanUtils.toBean(updateReqVO, CompanySystemTypeDO.class);
        companySystemTypeMapper.updateById(updateObj);
    }

    @Override
    public void deleteCompanySystemType(Long id) {
        // 校验存在
        validateCompanySystemTypeExists(id);
        // TODO 校验是否有关联文件，需等制度列表实现后加
        // 删除
        companySystemTypeMapper.deleteById(id);
    }

    private void validateCompanySystemTypeExists(Long id) {
        if (companySystemTypeMapper.selectById(id) == null) {
            throw exception(COMPANY_SYSTEM_TYPE_NOT_EXISTS);
        }
    }

    @Override
    public CompanySystemTypeDO getCompanySystemType(Long id) {
        return companySystemTypeMapper.selectById(id);
    }

    @Override
    public PageResult<CompanySystemTypeDO> getCompanySystemTypePage(CompanySystemTypePageReqVO pageReqVO) {
        return companySystemTypeMapper.selectPage(pageReqVO);
    }

    @Override
    public List<CompanySystemTypeDO> getCompanySystemTypeList(String name) {
        return companySystemTypeMapper.getCompanySystemTypeList(name);
    }

    @Override
    public List<CompanySystemTypeDO> getTypeList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return companySystemTypeMapper.selectBatchIds(ids);
    }

    @Override
    public List<CompanySystemTypeRespVO> getSystemTypeTreeByUser(Integer learnStatus, Long typeId,String name) {
        EmployeeDO employee = employeeService.getEmployeeById(EmployeeContextHolder.getEmployeeId());
        if(employee == null){
            throw exception(EMPLOYEE_NOT_EXISTS);
        }
        // 拿到用户和制度关联信息
        Collection<Long> deptIds = new ArrayList<>();
        deptIds.add(employee.getDeptId());
        List<CompanySystemDeptDO> systemDeptDOS = companySystemDeptService.getListByDeptId(deptIds);

        if (CollUtil.isEmpty(systemDeptDOS)) {
            return Collections.emptyList();
        }
        // 拿到和用户相关的制度，默认都是未学习的制度
        List<Long> ids = systemDeptDOS.stream().map(CompanySystemDeptDO::getCompanySystemId).collect(Collectors.toList());
        List<CompanySystemDO> systemDOS = companySystemService.getCompanySystemList(ids,name);
        // 按分类删选
        if (!typeId.equals(0L)) {
           systemDOS.removeIf(s -> !s.getTypeId().equals(typeId));
        }
        systemDOS.forEach(i -> i.setStatus(CompanySystemLearnEnum.UNLEARNED.getValue()));
        // 给已学习的制度加状态
        Collection<Long> employeeIds = new ArrayList<>();
        employeeIds.add(employee.getId());
        List<Long> learnIds = companySystemEmployeeService.getListByEmployeeId(employeeIds).stream().map(CompanySystemEmployeeDO::getCompanySystemId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(learnIds)) {
            systemDOS.forEach(i -> {
                if (learnIds.contains(i.getId())) {
                    i.setStatus(CompanySystemLearnEnum.LEARNED.getValue());
                }
            });
        }
        // 只查未学习
        if (learnStatus.equals(CompanySystemLearnEnum.UNLEARNED.getValue())) {
            systemDOS.removeIf(s -> learnIds.contains(s.getId()));
        }
        // 只查已学习
        if (learnStatus.equals(CompanySystemLearnEnum.LEARNED.getValue())) {
            systemDOS.removeIf(s -> !learnIds.contains(s.getId()));
        }

        return buildSystemTree(systemDOS, getCompanySystemParentList());

    }

    @Override
    public List<CompanySystemTypeRespVO> getSystemTypeTreeList(Long typeId) {
        Collection<Long> ids = new ArrayList<>();
        List<CompanySystemTypeDO> parentList = getCompanySystemParentList();
        List<Long> allIds = parentList.stream().map(CompanySystemTypeDO::getId).collect(Collectors.toList());
        // id为0，默认查全部分类
        if (typeId.equals(0L)) {
            ids.addAll(allIds);
        } else {
            ids.add(typeId);
        }
        return buildSystemTree(companySystemService.getCompanySystemListByTypeId(ids), parentList);
    }

    /**
     * 构建首页制度学习模块树形列表
     *
     * @param systemDOList 公司制度列表
     * @return
     */
    public List<CompanySystemTypeRespVO> buildSystemTree(List<CompanySystemDO> systemDOList, List<CompanySystemTypeDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<CompanySystemTypeTreeListRespVO> treeListRespVOS = CollectionUtils.convertList(list, i -> {
            CompanySystemTypeTreeListRespVO respVO = new CompanySystemTypeTreeListRespVO();
            respVO.setId(i.getId());
            respVO.setName(i.getName());
            respVO.setParentId(i.getParentId());
            return respVO;
        });

        Map<Long, List<CompanySystemTypeTreeListRespVO>> treeMap = treeListRespVOS.stream().collect(Collectors.groupingBy(CompanySystemTypeTreeListRespVO::getParentId));

        if (CollUtil.isEmpty(systemDOList)) {
            return Collections.emptyList();
        }

        // 获取最顶层
        List<CompanySystemTypeTreeListRespVO> topToLowerChild = new ArrayList<>();
        List<CompanySystemTypeTreeListRespVO> allTop = new ArrayList<>();
        // 查出一级父类制度分类
        List<CompanySystemTypeTreeListRespVO> topTree = treeMap.get(0L);

        for (CompanySystemTypeTreeListRespVO vo : topTree) {
            List<CompanySystemTypeTreeListRespVO> childrenList = new ArrayList<>();
            // 先添加归属在一级制度分类的制度信息
            List<CompanySystemDO> collect = systemDOList.stream().filter(i -> i.getTypeId().equals(vo.getId())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)) {
                List<CompanySystemTypeTreeListRespVO> respVOList = CollectionUtils.convertList(collect, c -> {
                    CompanySystemTypeTreeListRespVO respVO = new CompanySystemTypeTreeListRespVO();
                    respVO.setId(c.getId());
                    respVO.setName(c.getName());
                    respVO.setStatus(c.getStatus());
                    return respVO;
                });
                childrenList.addAll(respVOList);
            }
            // 递归查到所有的子类
            List<CompanySystemTypeTreeListRespVO> vos = setRootNode(treeMap, vo.getId(), topToLowerChild);
            if (CollUtil.isNotEmpty(vos)) {
                // 将子类替换成制度信息
                childrenList.addAll(setChildrenSystem(vos, systemDOList));
            }
            vo.setChildren(childrenList);
            allTop.addAll(childrenList);

        }

        // 查封面
        List<CompanySystemFileRespVo> coverFileRef = getCoverFileRef(CollectionUtils.convertList(allTop, CompanySystemTypeTreeListRespVO::getId));
        Map<Long, List<CompanySystemFileRespVo>> fileRespVoMap = CollectionUtils.convertMultiMap(coverFileRef, CompanySystemFileRespVo::getBizRecordId);
        // 返回值
        List<CompanySystemTypeRespVO> resultList = CollectionUtils.convertList(allTop, s -> {
            CompanySystemTypeRespVO vo = new CompanySystemTypeRespVO();
            vo.setId(s.getId());
            vo.setName(s.getName());
            vo.setCoverFileRef(CollUtil.isEmpty(fileRespVoMap.get(s.getId())) ? Collections.emptyList(): fileRespVoMap.get(s.getId()));
            vo.setLearnStatus(s.getStatus());
            return vo;
        });

        return resultList.stream().sorted(Comparator.comparing(CompanySystemTypeRespVO::getId)).collect(Collectors.toList());
    }

    /**
     * 获取制度封面
     *
     * @param ids
     * @return
     */
    public List<CompanySystemFileRespVo> getCoverFileRef(Collection<Long> ids) {
        FileRefQueryDTO refQueryDTO = FileRefQueryDTO.builder().bizType(BizTypeEnum.COMPANY_SYSTEM.getValue()).bizRecordIds(ids).build();
        List<FileRefRespDTO> fileRef = fileServiceProvider.getFileRef(refQueryDTO);
        fileRef.removeIf(i -> i.getBizFileType().equals(BizFileTypeEnum.FILE.getValue()));
        List<CompanySystemFileRespVo> list = BeanUtils.toBean(fileRef, CompanySystemFileRespVo.class);
        return list;
    }

    public CompanySystemTypeDO buildAllTopTree() {

        CompanySystemTypeDO typeDO = new CompanySystemTypeDO();
        typeDO.setName("全部");
        typeDO.setId(0L);
        typeDO.setParentId(0L);
        return typeDO;
    }

    public List<CompanySystemTypeTreeListRespVO> setChildrenSystem(List<CompanySystemTypeTreeListRespVO> childrenList, List<CompanySystemDO> systemDOList) {
        List<CompanySystemTypeTreeListRespVO> respVOList = new ArrayList<>();
        for (CompanySystemTypeTreeListRespVO vo : childrenList) {
            List<CompanySystemDO> collect = systemDOList.stream().filter(i -> i.getTypeId().equals(vo.getId())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)) {
                List<CompanySystemTypeTreeListRespVO> companySystemTypeTreeListRespVOS = CollectionUtils.convertList(collect, t -> {
                    CompanySystemTypeTreeListRespVO respVO = new CompanySystemTypeTreeListRespVO();
                    respVO.setId(t.getId());
                    respVO.setParentId(vo.getParentId());
                    respVO.setName(t.getName());
                    return respVO;
                });
                respVOList.addAll(companySystemTypeTreeListRespVOS);

            }

        }
        return respVOList;

    }

    /**
     * 递归查出所有根节点
     */
    public List<CompanySystemTypeTreeListRespVO> setRootNode(Map<Long, List<CompanySystemTypeTreeListRespVO>> treeMap, Long id, List<CompanySystemTypeTreeListRespVO> children) {

        if (!id.equals(0L)) { // “全部”类型单独处理
            // 用来存放当前子节点
            List<CompanySystemTypeTreeListRespVO> currentPidLowerChild = new ArrayList<>();

            List<CompanySystemTypeTreeListRespVO> childTreeNodes = treeMap.get(id);
            if (CollUtil.isEmpty(childTreeNodes)) {
                return null;
            }
            for (CompanySystemTypeTreeListRespVO treeNode : childTreeNodes) {
                List<CompanySystemTypeTreeListRespVO> lowerChild = setRootNode(treeMap, treeNode.getId(), currentPidLowerChild);
                if (CollUtil.isEmpty(lowerChild)) {
                    currentPidLowerChild.add(treeNode);
                }
            }
            children.addAll(currentPidLowerChild);
            return children;
        }
        return Collections.emptyList();
    }

    public List<CompanySystemTypeDO> getCompanySystemParentList() {
        List<CompanySystemTypeDO> list = companySystemTypeMapper.getCompanySystemParentList();
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        // 增加“全部”类型
        list.add(buildAllTopTree());
        return list.stream().sorted(Comparator.comparing(CompanySystemTypeDO::getId)).collect(Collectors.toList());
    }

    public void curdInitializeCompanyType() {
        CompanySystemTypeEnum[] values = CompanySystemTypeEnum.values();
        List<CompanySystemTypeDO> typeDOS = CollectionUtils.convertList(values, t -> {
            CompanySystemTypeDO typeDO = new CompanySystemTypeDO();
            typeDO.setName(t.getName());
            typeDO.setParentId(t.getParent());
            typeDO.setCode(t.getCode());
            return typeDO;
        });
        companySystemTypeMapper.insertBatch(typeDOS);
    }

}
